<?php

class AFView extends AFQueriable //extends AFModule
{
	protected $asd;

	private $content;
	private $vars = array();
	private $viewPath = NULL;
	private $viewFile = NULL;
	private $compiledFile = NULL;

	public $viewExt = 'view';

	public function __construct()
	{
	}

	public function queryHandler($key, $arguments)
	{
		if(count($arguments))
		{
			return $this->assign($key, $arguments[0]);
		}
		else
		{
			return isset($this->vars[$key]) ? $this->vars[$key] : NULL;
		}
	}

	public function assign($key, $value)
	{
		$this->vars[$key] = $value;
		return $this;
	}

	public function assignPairs($array)
	{
		foreach($array as $key => $value)
		{
			$this->assign($key, $value);
		}
		return $this;
	}

	public function load($viewFile)
	{
		$content = file_get_contents($viewFile . '.' . $this->viewExt);
		$this->content = $content;
		$this->viewPath = dirname($viewFile);
		$this->viewFile = $viewFile . '.' . $this->viewExt;
		return $this;
	}

	public function setRaw($content)
	{
		$this->content = $content;
		return $this;
	}

//	public function import($name, $source)
//	{
//		if($source instanceOf AFView)
//		{
//			$this->imports[$name] = $source;
//		}
//		else
//		{
//			$this->imports[$name] = (new AFView())->setRaw($source);
//		}
//	}

	public function render($return = FALSE)
	{
		if(!defined('AF_WEB_DOC_view'))
		{
			define('AF_WEB_DOC_view', TRUE);
		}

		$this->compiledFile = '/tmp/' . FN::slug($this->viewFile) . '_' . FN::hash($this->viewFile) . '.php';

		if(!$this->checkview())
		{
			$this->compileview();
		}

		return $this->executeview($return);
	}

	private function checkview()
	{
		return FALSE;
		if(!file_exists($this->compiledFile) || (filemtime($this->compiledFile) < filemtime($this->viewFile)))
		{
			return FALSE;
		}
		else
		{
			return TRUE;
		}
	}

	private function compileview()
	{
		// Templater options
		$options = new AFQueriable();

		// Remove comments
		$this->content = preg_replace('/([ \t]*)?<\*.*\*>([ \t]*)?/s' , '', $this->content);

		// Match whole tags
		$this->content = preg_replace_callback('/<[\$t]\s*([^\s].*)\s*[\$t]>/Us', function($match) use ($options){
			// Match tag parameters
			$tagName = NULL;
			$params = array();
			preg_match_all('/([\/\$]?[a-zA-Z0-9]+)(\s*=\s*("([^"]+)"|([^\s]+)))?/s', $match[1], $out, PREG_SET_ORDER);
			foreach($out as $param)
			{
				// Set tag name
				if(!$tagName)
				{
					$tagName = $param[1];
				}

				// Also, set as param
				$key = $param[1];
				if(isset($param[5]))
				{
					$value = $param[5];
				}
				elseif(isset($param[4]))
				{
					$value = $param[4];
				}
				else
				{
					$value = TRUE;
				}
				$params[$key] = $value;
			}

			$out = '';

			if($options->echo())
			{
				$out = '<!-- ' . $match[0] . ' -->'."\n";
			}

			switch($tagName)
			{
				case 'set':
					foreach(array_slice($params, 1) as $key => $value)
					{
						$options->$key($value);
					}
//					$out .= '';
					break;
				case 'src':
					return FN::highlightXML($this->content);
				case 'elif':
				case 'elseif':
					$else = TRUE;
				case 'if':
//					if FN::_va($params, 'cond'):
//						$cond = $params['cond'];
					if(FN::_va($params, 'odd'))
					{
						$cond = $this->vary($params['odd']) . ' % 2';
					}
					if(FN::_va($params, 'even'))
					{
						$cond = '! (' . $this->vary($params['odd']) . ' % 2)';
					}
					if(FN::_va($params, 'true'))
					{
						$cond = $this->vary($params['odd']) . ' ? TRUE : FALSE';
					}
					if(FN::_va($params, 'false'))
					{
						$cond = $this->vary($params['odd']) . ' ? FALSE : TRUE';
					}
					if(FN::_va($params, 'cond'))
					{
						$cond = $params['cond'];
					}
//						foreach($params as $k=>$v)
//						{
//							echo $k.': '.$v.'<br />';
//						}
					$out .=  '<?php '.(isset($else)?'else ':'').'if('.$cond.') { ?>';
					break;
				case 'else':
					$out .= '<?php } else { ?>';
					break;
				case 'loop':
					$params['key'] = FN::_va($params, 'key', 'key');
					$params['value'] = FN::_va($params, 'value', 'value');
					$out .= sprintf('<?php $__arrays[] = count(%s); foreach(%s as %s => %s) { ?>', $this->vary($params['loop']), $this->vary($params['loop']), $this->vary($params['key']), $this->vary($params['value']));
					break;
				case '/if':
				case '/loop':
					$out .= '<?php } ?>';
					break;
				case 'noloop':
					$out .= '<?php } if(array_pop($__arrays) > 0) { ?>';
					break;
				case 'import':
					$out .= '<?php (new AFView())->load("' . $this->viewPath . AF_SEP . $params['import'] . '")->assignPairs($__view_env)->render(); ?>';
					break;
				case 'doctype':
//					return '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"'."\n    ".'"http://www.w3.org/TR/html4/loose.dtd">';
					$out .= '<!DOCTYPE HTML>';
					break;
				case 'html':
					$params['xmlns'] = FN::_va($params, 'xmlns', 'http://www.w3.org/1999/xhtml');
					$params['lang'] = FN::_va($params, 'lang', 'en');
					$out .= '<html xmlns="'.$params['xmlns'].'" xml:lang="'.$params['lang'].'">';
					break;
				case '/html':
					$out .= '</html>';
					break;
				case 'title':
					$out .= '<title>'.$params[$tagName].'</title>';
					break;
				case 'meta':
					$out .= '<meta http-equiv="'.$params[$tagName].'" content="'.$params['content'].'" />';
					break;
				case 'link':
				case 'css':
					$params['rel'] = FN::_va($params, 'rel', 'stylesheet');
					$params['type'] = FN::_va($params, 'type', 'text/css');
					$out .= '<link rel="stylesheet" type="text/css" href="' . FN::trailingSlash(AF()->getPath()) . FN::trailingSlash($this->viewPath) . $params[$tagName] . '" />';
					break;
				case 'script':
				case 'js':
					$params['type'] = FN::_va($params, 'type', 'text/javascript');
					$params[$tagName] = FN::_va($params, $tagName, NULL);

					if($params[$tagName])
					{
						$out .= sprintf('<script type="%s" src="%s"></script>', $params['type'], FN::trailingSlash(AF()->getPath()) . FN::trailingSlash($this->viewPath) . $params[$tagName]);
					}
					else
					{
						$out .= sprintf('<script type="%s">', $params['type']);
					}
					break;
				case '/script':
				case '/js':
					$out .= '</script>';
					break;
				case 'echo':
					$out .= '<?php echo '.$this->vary($params[$tagName]).'; ?>';
					break;
				default:
					$out .= '<?php echo '.$this->vary($tagName).'; ?>';
			}

			return $out;
		}, $this->content);

		$compiledCode = "<?php\n\tclass_exists(\"AFView\") or die(\"Forbidden\");\n\t\$__view_draw = function(\$__view_env)\n\t{\n\t\tforeach(\$__view_env as \$__k=>\$__v)\n\t\t{\n\t\t\t\$\$__k = \$__v;\n\t\t}\n\t\t\$__arrays = array(); \n?>\n".$this->content."\n<?php\n\t}\n?>\n";

		file_put_contents($this->compiledFile, $compiledCode);
	}

	private function executeview($return)
	{
		if($return)
		{
			return $compiledCode;
		}
		else
		{
//			header('Content-type: text/html');
			include_once $this->compiledFile;
			$__view_draw($this->vars);
			unset($__view_draw);
			if(!$this->viewFile) unlink($this->compiledFile);
			return;
		}
	}

	private function vary($name, $reverse = FALSE)
	{
		return ($reverse xor ($name[0] == '$')) ? $name : '$'.$name;
	}
}

?>
